package com.centerm.bluetooth.lkl;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.centerm.bluetooth.core.controller.BluetoothController;
import com.centerm.bluetooth.core.controller.constants.BluetoothState;
import com.centerm.bluetooth.core.listener.IBluetoothFoundListener;
import com.centerm.bluetooth.core.listener.IBluetoothStateListener;
import com.centerm.bluetooth.ibridge.BluetoothIBridgeDevice;
import com.centerm.bluetooth.ibridge.constants.ChannelConfig;
import com.centerm.bluetooth.lkl.listener.ISwiperListener;
import com.centerm.bluetooth.lklcommon.controller.PBOCController;
import com.centerm.bluetooth.lklcommon.controller.PinController;
import com.centerm.bluetooth.lklcommon.controller.TerminalController;
import com.centerm.bluetooth.lklcommon.controller.TrackController;
import com.centerm.bluetooth.lklcommon.listener.IPBOCListener;
import com.centerm.bluetooth.lklcommon.listener.IPinListener;
import com.centerm.bluetooth.lklcommon.listener.ITerminalListener;
import com.centerm.bluetooth.lklcommon.listener.ITrackListener;
import com.centerm.bluetooth.lklcommon.mode.Track;
import com.centerm.util.Logger;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by linwenhui on 2017/5/12.
 */

public class SwiperController {
    private static SwiperController instance;
    private TrackController trackController;
    private PinController pinController;
    private PBOCController pbocController;
    private TerminalController terminalController;
    private POSImp posImp;
    private int mode;
    private String money;
    private int timeout;
    private BluetoothController bluetoothController;
    private ISwiperListener swiperListener;
    private static Handler mainHandler = new Handler(Looper.getMainLooper());
    private Timer searchTimer;
    private int inputMode;

    private SwiperController(Context context) {
        Logger.setDEBUG(false, false);
        ChannelConfig.getInstance().setChannel(ChannelConfig.LKL);
        posImp = new POSImp();
        bluetoothController = BluetoothController.getInstance(context);
        bluetoothController.setBluetoothFoundListener(posImp);
        bluetoothController.setBluetoothStateListener(posImp);
        trackController = new TrackController(context);
        trackController.setListener(posImp);
        pinController = new PinController(context);
        pinController.setListener(posImp);
        pbocController = new PBOCController(context);
        pbocController.setListener(posImp);
        terminalController = new TerminalController(context);
        terminalController.setListener(posImp);
    }

    public static SwiperController getInstance(Context context) {
        if (instance == null) {
            synchronized (SwiperController.class) {
                if (instance == null)
                    instance = new SwiperController(context);
            }
        }
        return instance;
    }

    public void setSwiperListener(ISwiperListener swiperListener) {
        this.swiperListener = swiperListener;
    }

    public void resetSDKStatus() {
        trackController.resetSDKStatus();
    }

    /**
     * @param timeout 单位秒
     */
    public void startDiscovery(int timeout) {
        bluetoothController.startDiscovery();
        searchTimer = new Timer();
        searchTimer.schedule(new SearchTimer(timeout * 1000), 1000, 1000);
    }

    public void connectBT(BluetoothIBridgeDevice device) {
        bluetoothController.connect(device);
    }

    public void disconnectBT(BluetoothIBridgeDevice device) {
        bluetoothController.disconnect(device);
    }

    public void reset() throws IOException{
        terminalController.onReset();
    }

    public boolean startSwiper(int mode, int timeout, String money, String tradeType, String extraInfo) throws IOException {
        this.mode = mode;
        this.money = money;
        this.timeout = timeout;
        inputMode = 0;
        return trackController.openTrackCardRead(mode, timeout, 0x01, tradeType, money, extraInfo);
    }

    public boolean startSwiperSafe(int mode, int timeout, String money, String tradeType, String extraInfo, String serviceCode, String featureCode, String extralInfo) throws IOException {
        this.mode = mode;
        this.money = money;
        this.timeout = timeout;
        inputMode = 1;
        return trackController.openTrackCardReadSafe(mode, timeout, 0x01, tradeType, money, extraInfo, serviceCode, featureCode, extralInfo);
    }

    private class SearchTimer extends TimerTask {

        private int timeout;

        public SearchTimer(int timeout) {
            this.timeout = timeout;
        }

        @Override
        public void run() {
            if (timeout > 0) {
                timeout -= 1000;
            } else {
                Logger.i(" == timeout == " + timeout);
                bluetoothController.stopDiscovery();
                cancel();
                if (searchTimer != null)
                    searchTimer.cancel();
            }

        }
    }

    private class POSImp implements IBluetoothStateListener, IBluetoothFoundListener, ITrackListener, IPinListener, IPBOCListener, ITerminalListener {

        private Track track;
        private int cardType;

        @Override
        public void onBluetoothStateChange(BluetoothState state) {
            if (state == BluetoothState.CONNECTED) {
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (swiperListener != null)
                            swiperListener.onConnected();
                    }
                });
            } else if (state == BluetoothState.DISCONNECTED) {
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (swiperListener != null)
                            swiperListener.onDisconnected();
                    }
                });
            } else if (state == BluetoothState.CONNECTTING) {
            } else {
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (swiperListener != null)
                            swiperListener.onConnectFailure();
                    }
                });
            }
        }

        @Override
        public void onDeviceFound(final BluetoothIBridgeDevice device) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onFound(device);
                }
            });
        }

        @Override
        public void onDiscoveryFinished() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onFoundEnd();
                }
            });
        }

        @Override
        public void onError(int code, final String msg) {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null) {
                        swiperListener.onError(msg);
                    }
                }
            });
        }

        @Override
        public void onTimeout() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onTimeout();
                }
            });
        }

        @Override
        public void onCardType(byte cardType) {
            Logger.i(" == onCardType == " + cardType);
            this.cardType = cardType;
            switch (cardType) {
                case 1:
                    try {
                        trackController.readTrackData(0x01 | 0x02 | 0x04, new byte[]{0x00, 0x00, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF,
                                (byte) 0xFF, 0x00, 0x00, 0x00});
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    break;
                case 2: {
//                    byte[] moneyBytes = money.getBytes();
                    try {
                        pbocController.startPBOC(money);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
                case 4: {
//                    byte[] moneyBytes = money.getBytes();
                    try {
                        pbocController.startQPBOC(money);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
            }
        }

        @Override
        public void onCardTypeSafe(byte cardType) {
            Logger.i(" == onCardTypeSafe == " + cardType);
            switch (cardType) {
                case 1:
                    try {
                        trackController.readTrackDataSafe(0x01 | 0x02 | 0x04, new byte[]{0x00, 0x00, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF,
                                (byte) 0xFF, 0x00, 0x00, 0x00});
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    break;
                case 2: {
//                    byte[] moneyBytes = money.getBytes();
                    try {
                        pbocController.startPBOC(money);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
                case 4: {
//                    byte[] moneyBytes = money.getBytes();
                    try {
                        pbocController.startQPBOC(money);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                break;
            }
        }

        @Override
        public void onSwiperSuc(final Track track) {
            Logger.i(track);
            this.track = track;
            if (inputMode == 0)
                try {
                    pinController.startInputPin(6, timeout);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            else if (inputMode == 1) {
                try {
                    pinController.startInputPinSafe(6, timeout, 0);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onSwiperError() {
            try {
                terminalController.onReset();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onSwiperError();
                }
            });
        }

        @Override
        public void onSwiperCancel() {
            try {
                terminalController.onReset();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onSwiperCancel();
                }
            });
        }

        @Override
        public void onSwiperTimeout() {
            try {
                terminalController.onReset();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onSwiperTimeout();
                }
            });
        }


        @Override
        public void onInputPinCancel() {
            if (cardType != 1)
                try {
                    pbocController.endPBOC(0);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            else
                try {
                    terminalController.onReset();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onInputCancel();
                }
            });
        }

        @Override
        public void onInputPin(String pinRandom, String pinBlock, String macRandom, String mac) {
            track.setPinRandom(pinRandom);
            track.setPinBlock(pinBlock);
            track.setMac(mac);
            track.setMacRandom(macRandom);
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onTradeSuc(track);
                }
            });
            if (cardType != 1)
                try {
                    pbocController.endPBOC(0);
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

        @Override
        public void onInputWaiter() {
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null) {
                        swiperListener.onInputWaiter();
                    }

                }
            });
        }

        @Override
        public void onPBOCSuc(Track track) {
            this.track = track;
            try {
                pinController.startInputPin(6, timeout);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onPBOCError() {
            try {
                terminalController.onReset();
            } catch (IOException e) {
                e.printStackTrace();
            }
            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (swiperListener != null)
                        swiperListener.onPBOCError();
                }
            });
        }

        @Override
        public void onEndPBOC() {
            try {
                terminalController.onReset();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onResetSuc() {

        }
    }

}
